#!/usr/bin/env python3
# -*- coding: utf-8 -*-

"""
账号控制组件模块

这个模块包含AccountWidget类，用于显示和管理单个账号的状态和操作。
这是代码结构优化的示例，展示如何将大型GUI文件拆分为更小的模块。
"""

import os
import time
import json
from PyQt6.QtWidgets import (QWidget, QVBoxLayout, QHBoxLayout, QPushButton,
                             QLabel, QLineEdit, QTextEdit, QMessageBox,
                             QGroupBox)
from PyQt6.QtCore import Qt, pyqtSignal, QEvent, QByteArray, QUrl
from PyQt6.QtGui import QPixmap
from PyQt6.QtNetwork import QNetworkAccessManager, QNetworkRequest, QNetworkReply

# 导入日志模块
from logger import app_logger as logger

# 导入自定义模块
from account_thread import AccountThread


class _UpdateAvatarEvent(QEvent):
    """自定义事件类，用于在UI线程中更新头像"""
    EVENT_TYPE = QEvent.Type(QEvent.registerEventType())

    def __init__(self, pixmap=None, text=None):
        super().__init__(_UpdateAvatarEvent.EVENT_TYPE)
        self.pixmap = pixmap
        self.text = text or "头像"

    def __str__(self):
        """用于调试的字符串表示"""
        if self.pixmap and not self.pixmap.isNull():
            return f"_UpdateAvatarEvent(pixmap={self.pixmap.width()}x{self.pixmap.height()})"
        else:
            return f"_UpdateAvatarEvent(text='{self.text}')"


class AccountWidget(QWidget):
    """账号控制组件，显示单个账号的状态和操作"""
    delete_requested = pyqtSignal(str)  # 请求删除账号的信号

    def __init__(self, port, account_data=None, parent=None):
        super().__init__(parent)
        self.port = port
        self.account_data = account_data or {}
        self.thread = None # 用于执行任务的线程
        self.network_manager = QNetworkAccessManager(self)
        self.initUI()

        # 记录初始化日志
        logger.debug(f"[端口:{self.port}] AccountWidget初始化")

    def event(self, event):
        """处理自定义事件"""
        if event.type() == _UpdateAvatarEvent.EVENT_TYPE:
            try:
                if event.pixmap and not event.pixmap.isNull():
                    # 确保图片有效再设置
                    self.avatar_label.setPixmap(event.pixmap)
                    self.avatar_label.setText("") # 清除文字
                    logger.debug(f"头像已更新: {event.pixmap.width()}x{event.pixmap.height()}")
                else:
                    # 如果图片无效，显示文本
                    self.avatar_label.setText(event.text)
                    self.avatar_label.setPixmap(QPixmap()) # 清除图片
                    logger.debug(f"显示头像文本: {event.text}")
                return True
            except Exception as e:
                logger.error(f"更新头像时出错: {str(e)}")
                # 出错时显示默认文本
                self.avatar_label.setText("头像")
                self.avatar_label.setPixmap(QPixmap()) # 清除图片
                return True
        return super().event(event)

    def handle_login_success(self, port, user_info):
        """处理登录成功信号，更新UI显示用户信息"""
        if str(port) != str(self.port):
            return

        # 更新账号数据
        self.account_data.update(user_info)

        # 更新UI显示
        self.nickname_label.setText(user_info.get('nickname', '未知昵称'))
        self.user_id_label.setText(user_info.get('user_id', '未知'))

        # 更新头像
        avatar_path = os.path.join("temp", "avatars", f"account_{self.port}.png")
        if os.path.exists(avatar_path):
            pixmap = QPixmap(avatar_path)
            if not pixmap.isNull():
                self.avatar_label.setPixmap(pixmap)
                self.avatar_label.setText("")

        logger.info(f"[端口:{self.port}] 账号登录成功，UI已更新")

    def initUI(self):
        """初始化UI组件"""
        # 初始化线程对象
        self.thread = AccountThread(self.port, "", [], 0)

        layout = QVBoxLayout()

        # 日志区域
        log_group = QGroupBox("日志")
        log_layout = QVBoxLayout()
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        log_layout.addWidget(self.log_text)
        log_group.setLayout(log_layout)

        # 顶部信息区域
        top_layout = QHBoxLayout()

        # 头像区域
        avatar_layout = QVBoxLayout()
        self.avatar_label = QLabel("头像")
        self.avatar_label.setFixedSize(80, 80)
        self.avatar_label.setAlignment(Qt.AlignmentFlag.AlignCenter)
        self.avatar_label.setStyleSheet("border: 1px solid #cccccc; border-radius: 5px;")
        self.avatar_label.setScaledContents(True)  # 设置图片自动缩放以适应标签大小
        avatar_layout.addWidget(self.avatar_label)
        avatar_layout.setAlignment(Qt.AlignmentFlag.AlignCenter)
        top_layout.addLayout(avatar_layout)

        # 账号信息区域
        info_layout = QVBoxLayout()

        # 昵称和状态
        name_status_layout = QHBoxLayout()
        self.nickname_label = QLabel(self.account_data.get('nickname', '未知昵称'))
        self.nickname_label.setStyleSheet("font-weight: bold; font-size: 14px;")
        name_status_layout.addWidget(self.nickname_label)

        self.status_label = QLabel("未启动")
        self.status_label.setStyleSheet("color: gray;")
        name_status_layout.addWidget(self.status_label)
        name_status_layout.addStretch()
        info_layout.addLayout(name_status_layout)

        # 用户ID
        user_id_layout = QHBoxLayout()
        user_id_layout.addWidget(QLabel("用户ID:"))
        self.user_id_label = QLabel(self.account_data.get('user_id', '未知'))
        user_id_layout.addWidget(self.user_id_label)
        user_id_layout.addStretch()
        info_layout.addLayout(user_id_layout)
        
        # 端口号
        port_layout = QHBoxLayout()
        port_layout.addWidget(QLabel("端口号:"))
        self.port_label = QLabel(str(self.port))
        port_layout.addWidget(self.port_label)
        port_layout.addStretch()
        info_layout.addLayout(port_layout)

        top_layout.addLayout(info_layout)
        top_layout.addStretch()

        # 按钮区域
        buttons_layout = QVBoxLayout()

        # 详情按钮
        self.details_btn = QPushButton("打开主页")
        try:
            self.details_btn.clicked.disconnect()
        except TypeError:
            pass
        self.details_btn.clicked.connect(self.open_xhs_homepage)
        buttons_layout.addWidget(self.details_btn)

        # 删除按钮
        self.delete_btn = QPushButton("删除账号")
        self.delete_btn.clicked.connect(self.request_delete)
        buttons_layout.addWidget(self.delete_btn)

        top_layout.addLayout(buttons_layout)

        layout.addLayout(top_layout)

        # 关键词设置
        keywords_group = QGroupBox("搜索关键词")
        keywords_layout = QVBoxLayout()
        self.keywords_edit = QLineEdit(self.account_data.get('keywords', ''))
        self.keywords_edit.textChanged.connect(self.save_keywords)
        keywords_layout.addWidget(self.keywords_edit)
        keywords_group.setLayout(keywords_layout)
        layout.addWidget(keywords_group)

        # 回复话术设置
        replies_group = QGroupBox("回复话术")
        replies_layout = QVBoxLayout()
        self.replies_edit = QTextEdit()

        # 设置回复话术文本
        replies = self.account_data.get('replies', [])
        if isinstance(replies, list):
            self.replies_edit.setPlainText('\n'.join(replies))
        else:
            self.replies_edit.setPlainText(str(replies))

        self.replies_edit.textChanged.connect(self.save_replies)
        replies_layout.addWidget(self.replies_edit)
        replies_group.setLayout(replies_layout)
        layout.addWidget(replies_group)
        
        # 最大帖子数设置
        max_posts_group = QGroupBox("最大帖子数")
        max_posts_layout = QVBoxLayout()
        self.max_posts_edit = QLineEdit(str(self.account_data.get('max_posts', 5)))
        self.max_posts_edit.textChanged.connect(self.save_max_posts)
        max_posts_layout.addWidget(self.max_posts_edit)
        max_posts_group.setLayout(max_posts_layout)
        layout.addWidget(max_posts_group)

        # 操作按钮区域
        btn_layout = QHBoxLayout()
        self.start_btn = QPushButton("开始任务")
        self.start_btn.clicked.connect(self.start_task)
        btn_layout.addWidget(self.start_btn)

        self.stop_btn = QPushButton("停止任务")
        self.stop_btn.clicked.connect(self.stop_task)
        self.stop_btn.setEnabled(False)
        btn_layout.addWidget(self.stop_btn)

        layout.addLayout(btn_layout)

        # 添加日志区域到主布局
        layout.addWidget(log_group)

        self.setLayout(layout)

        # 连接信号
        self.thread.login_success.connect(self.handle_login_success)

        # 根据登录状态设置UI
        self.update_ui_by_login_status()

    def update_ui_by_login_status(self):
        """根据登录状态更新UI"""
        is_logged = self.account_data.get('is_logged', False)

        if is_logged:
            self.start_btn.setEnabled(True)
            self.update_log("账号已登录，可以开始任务")
        else:
            self.start_btn.setEnabled(False)
            self.update_log("账号未登录，请先删除此账号，然后通过'添加新账号'重新登录")

    def update_account_data(self, data):
        """更新账号数据"""
        if not isinstance(data, dict):
            logger.error(f"更新账号数据失败: 数据类型错误 {type(data)}")
            return

        # 更新数据
        self.account_data.update(data)

        # 更新UI显示
        self.nickname_label.setText(self.account_data.get('nickname', '未知昵称'))
        self.user_id_label.setText(self.account_data.get('user_id', '未知'))

        # 如果有头像URL，加载头像
        if 'avatar' in data and data['avatar']:
            self.load_avatar(data['avatar'])

        # 更新登录状态UI
        self.update_ui_by_login_status()

        logger.debug(f"账号数据已更新: {self.port}")

    def load_avatar(self, url):
        """加载头像图片 - 统一使用PNG格式"""
        if not url:
            return

        logger.debug(f"开始加载头像: {url}")

        # 创建avatars目录
        avatar_dir = os.path.join("temp", "avatars")
        os.makedirs(avatar_dir, exist_ok=True)

        # 统一使用PNG格式保存头像
        save_path = os.path.join(avatar_dir, f"account_{self.port}.png")

        # 如果本地已有头像文件，直接加载
        if os.path.exists(save_path):
            pixmap = QPixmap(save_path)
            if not pixmap.isNull():
                logger.debug(f"从本地加载头像: {save_path}")
                self.avatar_label.setPixmap(pixmap)
                self.avatar_label.setText("") # 清除文字
                return

        # 从网络下载头像
        try:
            request = QNetworkRequest(QUrl(url))
            reply = self.network_manager.get(request)
            reply.finished.connect(lambda: self.handle_avatar_download(reply, save_path))
            logger.debug(f"开始下载头像: {url}")
        except Exception as e:
            logger.error(f"请求头像失败: {str(e)}")

    def handle_avatar_download(self, reply, save_path):
        """处理头像下载完成事件 - 统一使用PNG格式"""
        try:
            if reply.error():
                logger.error(f"下载头像出错: {reply.errorString()}")
                return

            # 获取响应数据
            response = reply.readAll()

            # 尝试使用PIL处理图片并转换为PNG
            try:
                # 尝试导入PIL库
                from PIL import Image
                import io

                # 从内存中加载图片
                img = Image.open(io.BytesIO(response.data()))
                logger.debug(f"PIL成功加载图片: {img.format}, {img.size}")

                # 转换为PNG格式并保存
                img.save(save_path, 'PNG')
                logger.debug(f"图片已保存为PNG: {save_path}")

                # 加载转换后的图片
                pixmap = QPixmap(save_path)
                if not pixmap.isNull():
                    self.avatar_label.setPixmap(pixmap)
                    self.avatar_label.setText("") # 清除文字
                    logger.debug("PNG头像加载成功")
                    return
            except ImportError:
                logger.warning("PIL库未安装，无法处理图片。请安装PIL: pip install pillow")
            except Exception as e:
                logger.error(f"使用PIL处理图片时出错: {str(e)}")

            # 如果PIL不可用或失败，尝试使用Qt直接处理
            pixmap = QPixmap()
            if pixmap.loadFromData(response.data()):
                # 保存为PNG
                pixmap.save(save_path, 'PNG')
                logger.debug(f"使用Qt保存图片为PNG: {save_path}")

                # 设置头像
                self.avatar_label.setPixmap(pixmap)
                self.avatar_label.setText("") # 清除文字
                logger.debug("使用Qt加载头像成功")
                return
            else:
                logger.warning("使用Qt加载图片失败")
                self.avatar_label.setText("加载失败")

        except Exception as e:
            logger.error(f"处理头像下载时出错: {str(e)}")
            self.avatar_label.setText("加载失败")

    def update_status(self, status):
        """更新状态显示"""
        self.status_label.setText(status)
        logger.info(f"账号 {self.port} 状态更新: {status}")

    def update_log(self, log):
        """更新日志显示"""
        self.log_text.append(log)
        # 自动滚动到底部
        self.log_text.verticalScrollBar().setValue(self.log_text.verticalScrollBar().maximum())
        # 同时记录到系统日志
        try:
            if hasattr(self, 'port') and self.port:
                logger.info(f"[账号 {self.port}] {log}")
            else:
                logger.info(f"[账号 未知] {log}")
        except KeyError:
            logger.info(f"[账号 未知] {log}")

    def start_task(self):
        """开始执行任务"""
        # 检查登录状态
        if not self.account_data.get('is_logged', False):
            QMessageBox.warning(self, "操作失败", "账号未登录或登录状态未知。\n请先删除此账号，然后通过'添加新账号'重新登录。")
            return

        # 获取设置的参数
        keywords = self.keywords_edit.text().strip()
        replies_text = self.replies_edit.toPlainText().strip()

        if not keywords:
            QMessageBox.warning(self, "参数错误", "请输入搜索关键词")
            return

        if not replies_text:
            QMessageBox.warning(self, "参数错误", "请输入回复话术")
            return

        # 将回复话术文本转换为数组
        replies_array = [line.strip() for line in replies_text.split('\n') if line.strip()]

        # 保存设置
        self.account_data['keywords'] = keywords
        self.account_data['replies'] = replies_array

        # 更新界面状态
        self.start_btn.setEnabled(False)
        self.stop_btn.setEnabled(True)
        self.keywords_edit.setEnabled(False)
        self.replies_edit.setEnabled(False)

        # 获取端口号
        port = self.account_data.get('port')
        if not port:
            QMessageBox.critical(self, "错误", "账号数据缺少端口信息，无法启动任务。")
            # 恢复按钮状态
            self.start_btn.setEnabled(True)
            self.stop_btn.setEnabled(False)
            self.keywords_edit.setEnabled(True)
            self.replies_edit.setEnabled(True)
            return

        # 创建并启动线程
        # Ensure thread_id is a string and pass the correct account_data dictionary
        self.thread = AccountThread(thread_id=str(self.port), account_data=self.account_data)
        self.thread.status_updated.connect(self.update_status)
        self.thread.log_updated.connect(lambda acc_port, msg: self.update_log(msg))
        self.thread.login_success.connect(lambda acc_port, info: self.update_account_data(info))
        self.thread.finished.connect(self.task_finished)

        # 更新状态并记录日志
        self.update_status("正在启动任务...")
        self.update_log("开始任务")

        self.thread.start()
        logger.info(f"账号 {self.port} 开始执行任务")

    def stop_task(self):
        """停止执行任务"""
        if self.thread and self.thread.is_running:
            self.thread.stop()
            self.update_log("正在停止任务...")
            self.start_btn.setEnabled(True) # 重新启用开始按钮
            self.stop_btn.setEnabled(False) # 禁用停止按钮
            logger.info(f"账号 {self.port} 停止任务")

    def task_finished(self):
        """任务完成后恢复界面状态"""
        self.start_btn.setEnabled(True)
        self.stop_btn.setEnabled(False)
        self.keywords_edit.setEnabled(True)
        self.replies_edit.setEnabled(True)
        self.thread = None # 清理线程引用
        logger.info(f"账号 {self.port} 任务已完成")

    def save_keywords(self):
        """实时保存关键词"""
        keywords = self.keywords_edit.text()
        if self.account_data.get('keywords') != keywords:
            self.account_data['keywords'] = keywords
            self.update_log(f"关键词已更新并保存: {keywords}")
            # 发送信号通知主窗口保存账号数据
            main_window = self.window()
            if hasattr(main_window, 'saveAccounts'):
                main_window.saveAccounts()
            else:
                self.update_log("警告：无法保存到文件，未找到saveAccounts方法")
                
    def save_replies(self):
        """保存回复话术到账号数据"""
        replies = self.replies_edit.toPlainText().split('\n')
        self.account_data['replies'] = [r.strip() for r in replies if r.strip()]
        logger.debug(f"[端口:{self.port}] 保存回复话术: {self.account_data['replies']}")
        # 发送信号通知主窗口保存账号数据
        main_window = self.window()
        if hasattr(main_window, 'saveAccounts'):
            main_window.saveAccounts()
        else:
            self.update_log("警告：无法保存到文件，未找到saveAccounts方法")
        
    def save_max_posts(self):
        """保存最大发帖数到账号数据"""
        try:
            max_posts = int(self.max_posts_edit.text())
            self.account_data['max_posts'] = max_posts
            logger.debug(f"[端口:{self.port}] 保存最大发帖数: {max_posts}")
            # 发送信号通知主窗口保存账号数据
            main_window = self.window()
            if hasattr(main_window, 'saveAccounts'):
                main_window.saveAccounts()
            else:
                self.update_log("警告：无法保存到文件，未找到saveAccounts方法")
        except ValueError:
            logger.warning(f"[端口:{self.port}] 无效的最大发帖数输入")

    def request_delete(self):
        """请求删除账号"""
        # 单一确认框
        reply = QMessageBox.question(self, "确认删除",
                                    "确定要删除该账号吗？此操作将停止所有运行中的任务并删除账号数据",
                                    QMessageBox.Yes | QMessageBox.No)
        if reply == QMessageBox.Yes:
            # 如果任务正在运行，先停止
            if self.thread and self.thread.is_running:
                self.stop_task()
            self.delete_requested.emit(str(self.port))
            logger.info(f"账号 {self.port} 请求删除")

    def open_xhs_homepage(self):
        from threading import Thread
        
        def _open_homepage():
            from DrissionPage import ChromiumPage, ChromiumOptions
            try:
                port = self.account_data.get('port')
                nickname = self.account_data.get('nickname', '未知昵称')
                
                # 记录日志
                logger.info(f"正在为账号 {nickname} (端口: {port}) 打开小红书主页")
                self.update_log(f"正在打开小红书主页...")

                if port:
                    # 使用端口号作为用户数据目录
                    user_data_dir = os.path.join("temp", "user_data", f"port_{port}")

                    # 创建ChromiumOptions并设置参数
                    co = ChromiumOptions()
                    co.set_user_data_path(user_data_dir)
                    co.set_local_port(port)

                    # 使用配置好的ChromiumOptions创建页面对象
                    page = ChromiumPage(addr_or_opts=co)
                    page.get("https://www.xiaohongshu.com/")
                    
                    # 记录成功日志
                    logger.info(f"成功为账号 {nickname} 打开小红书主页")
                    self.update_log(f"小红书主页已成功打开")
                else:
                    # 如果没有配置端口，直接打开小红书主页
                    page = ChromiumPage()
                    page.get("https://www.xiaohongshu.com/")
                    
                    # 记录成功日志
                    logger.info(f"成功为账号 {nickname} 打开小红书主页 (无端口)")
                    self.update_log(f"小红书主页已成功打开")
            except Exception as e:
                logger.error(f"为账号 {nickname} 打开小红书主页失败: {str(e)}")
                self.update_log(f"打开小红书主页失败: {str(e)}")
        
        # 创建并启动线程
        thread = Thread(target=_open_homepage)
        thread.daemon = True
        thread.start()
